package org.thirdeyetvg.ncanreader.helper;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import nl.siegmann.epublib.domain.Book;
import nl.siegmann.epublib.domain.Resource;
import nl.siegmann.epublib.domain.TOCReference;
import nl.siegmann.epublib.epub.EpubReader;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import android.widget.TextView;

public class CustomEpubReader {

	public static enum NAV_MODE {
		spine, TOC
	}

	TextReaderUtil textReader;
	private Book book;

	private List<TOCReference> tocResourceList = new ArrayList<TOCReference>();;

	private NAV_MODE currentNavMode = NAV_MODE.spine;

	private int currentNavIndex = -1;
	private TextView tv;

	public CustomEpubReader(String fileName, TextView tv) throws IOException {
		// this.fileName = fileName;
		EpubReader epubReader = new EpubReader();
		book = epubReader.readEpubLazy(fileName, null);
		populateTOCReferenceList(book.getTableOfContents().getTocReferences());
		this.tv = tv;
	}

	private void clearResource(Resource resource) {
		if (resource != null) {
			resource.close();
		}
	}

	public int getCurrentPageNumber() {
		return currentNavIndex;
	}

	private Resource getCurrentResource() {
		try {
			switch (currentNavMode) {
			case spine:
				return book.getSpine().getSpineReferences()
						.get(currentNavIndex).getResource();
			case TOC:
				return tocResourceList.get(currentNavIndex).getResource();
			default:
				break;
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null;
	}

	private Resource getNextEpubPage() {
		clearResource(getCurrentResource());
		currentNavIndex++;
		return getCurrentResource();
	}

	/*
	 * public void logTableOfContents(List<TOCReference> tocReferences, int
	 * depth) { if (tocReferences == null) { return; } for (TOCReference
	 * tocReference : tocReferences) { StringBuilder tocString = new
	 * StringBuilder(); for (int i = 0; i < depth; i++) {
	 * tocString.append("\t"); } tocReference.getResource();
	 * tocString.append(tocReference.getTitle());
	 * System.out.println(tocString.toString() + " - " +
	 * tocReference.getCompleteHref() + " - " + tocReference.getResourceId());
	 * logTableOfContents(tocReference.getChildren(), depth + 1); } }
	 * 
	 * public void logTableOfContents() {
	 * logTableOfContents(book.getTableOfContents().getTocReferences(), 0); }
	 * 
	 * void logSpine() { List<SpineReference> spineReferences = book.getSpine()
	 * .getSpineReferences(); for (SpineReference spineReference :
	 * spineReferences) {
	 * System.out.println(spineReference.getResource().getHref()); } }
	 * 
	 * void logContent() { List<Resource> contents = book.getContents(); for
	 * (Resource resource : contents) { System.out.println(resource.getHref());
	 * } }
	 */
	public String nextPage() {
		String nextTextPage = getNextTextPage();
		if (nextTextPage == null) {
			Resource currentEpubPage = getCurrentResource();
			Resource nextEpubPage = getNextEpubPage();
			// TODO Fix this with optimal navigation to the exact location
			// In TOC Navigation same resource may be represented in
			// consequetive
			// indexes. To avoid reloading of the same resource, index is
			// incremented until new resource is found
			while (isSameResource(currentEpubPage, nextEpubPage)) {
				nextEpubPage = getNextEpubPage();
			}

			if (nextEpubPage == null) {
				System.out.println("Last page reached");
				currentNavIndex--;
			} else {
				System.out.println("Reading new epub page");
				parseResourceAndPopulateTextReader(nextEpubPage);
				return getNextTextPage();
			}
		} else {
			return nextTextPage;
		}
		return null;
	}

	private String getNextTextPage() {
		if (textReader != null) {
			return textReader.nextPage();
		}
		return null;
	}

	private Resource getPreviousEpubPage(){
		clearResource(getCurrentResource());
		currentNavIndex--;
		return getCurrentResource();
	}

	public String previousPage(){
		String previousTextPage = getPreviousTextPage();
		if (previousTextPage == null) {
			Resource currentEpubPage = getCurrentResource();
			Resource previousEpubPage = getPreviousEpubPage();
			// TODO Fix this with optimal navigation to the exact location
			// In TOC Navigation same resource may be represented in
			// consequetive
			// indexes. To avoid reloading of the same resource, index is
			// incremented until new resource is found
			while (isSameResource(currentEpubPage, previousEpubPage)) {
				previousEpubPage = getPreviousEpubPage();
			}

			if (previousEpubPage == null) {
				System.out.println("First page reached");
				currentNavIndex++;
			} else {
				System.out.println("Reading new epub page");
				parseResourceAndPopulateTextReader(previousEpubPage);

				return getPreviousTextPage();
			}
		} else {
			return previousTextPage;
		}
		return null;
	}

	private String getPreviousTextPage() {
		if (textReader != null) {
			return textReader.previousPage();
		}
		return null;
	}

	private boolean isSameResource(Resource resource1, Resource resource2) {
		if (resource2 != null && resource1 != null && resource2.getId() != null
				&& resource1.getId() != null
				&& resource1.getId().equalsIgnoreCase(resource2.getId())) {
			return true;
		} else {
			return false;
		}
	}

	private void parseResourceAndPopulateTextReader(Resource resource) {
		InputStream in;
		try {
			in = resource.getInputStream();

			Document doc = Jsoup.parse(in, resource.getInputEncoding(), "");
			System.out.println(doc.text());
			textReader = new TextReaderUtil(doc.text(), tv);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void populateTOCReferenceList(List<TOCReference> tocReferences) {
		if (tocReferences == null) {
			return;
		}
		for (TOCReference tocReference : tocReferences) {
			tocResourceList.add(tocReference);
			populateTOCReferenceList(tocReference.getChildren());
		}
	}

	public void setCurrentNavMode(NAV_MODE currentNavMode) {
		this.currentNavMode = currentNavMode;
	}

	public void setCurrentPageNumber(int currentPageNumber) {
		this.currentNavIndex = currentPageNumber;
	}

}
